package com.xuzm.netty.server;

import com.xuzm.netty.dto.ServerHandlerConsumer;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.DelimiterBasedFrameDecoder;
import io.netty.handler.codec.LineBasedFrameDecoder;
import io.netty.handler.codec.string.StringDecoder;
import io.netty.handler.codec.string.StringEncoder;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import sun.plugin2.message.Conversation;
import sun.plugin2.message.HeartbeatMessage;

import java.net.StandardSocketOptions;

/**
 * netty服务器
 */
@Slf4j
public class NettyServer {
    /**服务器端口*/
    private final int port;
    /**操作实体*/
    private final ServerHandlerConsumer consumer;

    public NettyServer(int port, ServerHandlerConsumer consumer) {
        this.port = port;
        this.consumer = consumer;
    }

    public void start() throws Exception {
        // 两个 EventLoopGroup 分别对应客户端和服务端
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();

        try {
            // 创建 ServerBootstrap 实例
            ServerBootstrap bootstrap = new ServerBootstrap();
            bootstrap.group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    // 设置连接超时时间
                    .option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 5000)
                    // 接收客户端连接请求的队列长度
                    .option(ChannelOption.SO_BACKLOG, 100)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            // 添加编码器和解码器
                            // 使用换行为分隔符
                            ch.pipeline().addLast(new LineBasedFrameDecoder(8192));
                            ch.pipeline().addLast(new StringDecoder());
                            ch.pipeline().addLast(new StringEncoder());
                            // 设置读写空闲时间
                            ch.pipeline().addLast(new IdleStateHandler(10, 0, 0));
                            // 添加自定义处理器▌
                            ch.pipeline().addLast(getHandlerAdapter());
                        }
                    });
            ChannelFuture channelFuture = bootstrap.bind(port).sync();
            Channel channel = channelFuture.channel();
            channel.closeFuture().sync();
        }catch (Exception e){
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            throw e;
        }
    }

    /**
     * 手动关闭服务器
     * @param channel 服务器通道
     * @param bossGroup 服务端的group
     * @param workerGroup 客户端的group
     */
    private void showDown(Channel channel, EventLoopGroup bossGroup, EventLoopGroup workerGroup){
        if(channel != null){
            channel.close();
        }
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
    }


    /**
     * 自定义处理器
     */
    public ChannelInboundHandlerAdapter getHandlerAdapter(){
        return new ChannelInboundHandlerAdapter(){
            /**错过心跳的最大次数*/
            private static final int MAX_MISSED_HEARTBEATS = 3;
            /**错过心跳次数*/
            private int missedHeartbeats = 0;

            @Override
            public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
                consumer.getAddConsumer().accept(ctx);
            }

            @Override
            public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
                if(!(msg instanceof HeartbeatMessage)) {
                    consumer.getReadConsumer().accept(ctx, msg);
                }else {
                    missedHeartbeats = 0;
                }
                super.channelRead(ctx, msg);
            }

            @Override
            public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
                consumer.getRemoveConsumer().accept(ctx);
            }

            @Override
            public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
                consumer.getExceptionConsumer().accept(ctx, cause);
                // 处理异常
                cause.printStackTrace();
                ctx.close();
            }

            /**
             * 用户事件触发
             *
             * 当 IdleStateHandler 发现读超时后，会调用 fireUserEventTriggered() 去执行后一个 Handler 的 userEventTriggered 方法。
             * 所以，根据心跳检测状态去关闭连接的就写在这里！
             */
            @Override
            public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
                if (evt instanceof IdleStateEvent) {
                    missedHeartbeats++;
                    if (missedHeartbeats >= MAX_MISSED_HEARTBEATS) {
                        System.out.println("Client disconnected due to missed heartbeats: " + ctx.channel().remoteAddress());
                        ctx.close();
                    } else {
                        ctx.writeAndFlush(new HeartbeatMessage(new Conversation(true,1)));
                    }
                } else {
                    super.userEventTriggered(ctx, evt);
                }
            }
        };
    }
}